package com.flute.icrawler.app.monitor;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;

import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.ReflectionException;

public class CrawlMonitor implements DynamicMBean {

	public String name;
	public Long loadedUrl;
	public Long allUrl;

	private String className;
	private String description;
	private MBeanAttributeInfo[] mbeanAttributeInfos;
	private MBeanConstructorInfo[] mbeanConstructorInfos;
	private MBeanOperationInfo[] mbeanOperationInfos;
	private MBeanNotificationInfo[] mBeanNotificationInfoArray;

	private MBeanInfo mBeanInfo = null;

	// monitored class
	public CrawlMonitoredEntity monitoredEntity;

	public CrawlMonitor(CrawlMonitoredEntity monitoredEntity) {

		className = this.getClass().getName();
		description = "Simple implementation of a dynamic MBean";

		this.monitoredEntity = monitoredEntity;

	}

	public Object getAttribute(String attribute)
			throws AttributeNotFoundException, MBeanException,
			ReflectionException {

		if (monitoredEntity.containReadAttribute(attribute)) {
			try {
				return monitoredEntity.getGetMethod(attribute).invoke(
						monitoredEntity.getMonitoredObject());
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}

		return null;
	}

	public AttributeList getAttributes(String[] attributeNames) {
		if (attributeNames == null)
			return null;
		AttributeList resultList = new AttributeList();
		// if attributeNames is empty, return an empty result list
		if (attributeNames.length == 0)
			return resultList;
		for (int i = 0; i < attributeNames.length; i++) {
			try {
				Object value = getAttribute(attributeNames[i]);
				resultList.add(new Attribute(attributeNames[i], value));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return resultList;
	}

	public MBeanInfo getMBeanInfo() {

		try {

			// 设置构造函数
			buildConstructor();

			// 设置属性值获取函数
			buildAttributes();

			buildOperation();

		} catch (Exception e) {
			e.printStackTrace();
		}

		mBeanInfo = new MBeanInfo(monitoredEntity.getMonitoredObject()
				.getClass().getName(), "monitor the serverImpl",
				mbeanAttributeInfos, mbeanConstructorInfos,
				mbeanOperationInfos, null);

		return mBeanInfo;
	}

	/**
	 * 设置一些被监控对象中指定的方法映射
	 */
	private void buildOperation() {
		// set operation
		// MBeanParameterInfo[] params = null;
		// operations[0] = new MBeanOperationInfo("printJobInfo",
		// "print the job's information", params, "void",
		// MBeanOperationInfo.INFO);
		//
		// mBeanInfo = new MBeanInfo(className, description, attributes,
		// constructorsInfo, operations, mBeanNotificationInfoArray);

	}

	private void buildAttributes() {

		String[] fields = monitoredEntity.getMonitoredFieldNames();

		int fieldsSize = fields.length;

		mbeanAttributeInfos = new MBeanAttributeInfo[fieldsSize];

		for (int i = 0; i < fieldsSize; i++) {
			try {
				mbeanAttributeInfos[i] = new MBeanAttributeInfo(fields[i],
						"name:crawlJob's name",
						monitoredEntity.getGetMethod(fields[i]), null);
			} catch (IntrospectionException e) {
				e.printStackTrace();
			}
		}

	}

	private void buildConstructor() {
		Constructor[] thisConstructors = monitoredEntity.getMonitoredObject()
				.getClass().getConstructors();
		int constructorsCount = thisConstructors.length;
		mbeanConstructorInfos = new MBeanConstructorInfo[constructorsCount];

		for (int i = 0; i < constructorsCount; i++) {
			mbeanConstructorInfos[i] = new MBeanConstructorInfo(
					thisConstructors[i].getName() + i, thisConstructors[i]);
		}

	}

	public Object invoke(String actionName, Object[] params, String[] signature)
			throws MBeanException, ReflectionException {

		// invoke method printJobInfo
		if (actionName.equals("printJobInfo")) {
			System.out.println("Job's name:");
			return null;
		} else {

			// unrecognized operation name
			throw new ReflectionException(
					new NoSuchMethodException(actionName),
					"Cannot find the operation " + actionName + " in "
							+ className);
		}

	}

	public void setAttribute(Attribute attribute)
			throws AttributeNotFoundException, InvalidAttributeValueException,
			MBeanException, ReflectionException {

		if (null == attribute)
			return;
		String name = attribute.getName();
		Object value = attribute.getValue();
		Method method = null;

		if (monitoredEntity.containWriteAttribute(name)) {
			method = monitoredEntity.getSetMethod(name);
		}

		if (method.getParameterTypes()[0].isAssignableFrom(value.getClass())) {

			try {
				method.invoke(monitoredEntity.getMonitoredObject(), value);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}

	}

	public AttributeList setAttributes(AttributeList attributes) {
		if (attributes == null)
			return null;
		AttributeList resultList = new AttributeList();
		// if attributeNames is empty, nothing more to do
		if (attributes.isEmpty())
			return resultList;
		// for each attribute, try to set it and add to the result list if
		// successfull
		for (Iterator i = attributes.iterator(); i.hasNext();) {
			Attribute attr = (Attribute) i.next();
			try {
				setAttribute(attr);
				String name = attr.getName();
				Object value = getAttribute(name);
				resultList.add(new Attribute(name, value));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return resultList;
	}

}
